#include "fmacros.h"
#include "anet.h"
#include <sys/socket.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

void anetSetError(char *err, const char *fmt, ...) {
    if (!err) return;

    va_list ap;
    va_start(ap, fmt);
    vsnprintf(err, ANET_ERR_LEN, fmt, ap);
    va_end(ap);
}

int anetTcpServer(char *err, int port, char *bindaddr, int backlog) {
    return _anetTcpServer(err, port, bindaddr, AF_INET, backlog);
}

int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog) {
    if (bind(s, sa, len) == -1) {
        anetSetError(err, "bind: %s", strerror(errno));
        close(s);
        return ANET_ERR;
    }

    if (listen(s, backlog)) {
        anetSetError(err, "listen: %s", strerror(errno));
        close(s);
        return ANET_ERR;
    }

    return ANET_OK;
}

int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backlog) {
    int s = -1, rv;
    char _port[6];
    struct addrinfo hints, *servinfo, *p;

    snprintf(_port, 6, "%d", port);
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = af;
    hints.ai_socktype = SOCK_STREAM;

    // 获取网络地址信息
    if ((rv = getaddrinfo(bindaddr, _port, &hints, &servinfo)) != 0) {
        return ANET_ERR;
    }
    
    // 根据网络地址信息创建套接字，并绑定监听端口
    for (p = servinfo; p; p = p->ai_next) {
        if ((s = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
            continue;

        if (anetListen(err, s, p->ai_addr, p->ai_addrlen, backlog) == ANET_ERR) goto error;
        goto end;
    }

    if (p == NULL) {
        anetSetError(err, "unable to bind socket, errno: %d", errno);
        goto error;
    }

error:
    if (s != -1) close(s);
    s = ANET_ERR;
end:
    freeaddrinfo(servinfo);
    return s;
}

int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
    int fd;
    fd = accept(s, sa, len);
    return fd;
}

// 接收来自客户端请求的回调函数
int anetTcpAccept(char *err, int s, char *ip, size_t ip_len, int *port) {
    int fd;
    struct sockaddr_storage sa;
    socklen_t salen = sizeof(sa);
    // 此时来自客户端的数据数据已经准备好了，即s可读，所以调用accept不会发生阻塞
    if ((fd = anetGenericAccept(err, s, (struct sockaddr *)&sa, &salen)) == -1)
        return ANET_ERR;

    // 保存一些参数
    if (sa.ss_family == AF_INET) {
        struct sockaddr_in *s = (struct sockaddr_in *)&sa;
        if (ip) inet_ntop(AF_INET, &s->sin_addr, ip, ip_len);
        if (port) *port = ntohs(s->sin_port);
    } else {

    }

    return fd;
}